%{ 
	import java.io.*; 
%} 

/*%token true false*/

%token INT DOUBLE BOOLEAN String

%token Player Dice Cell

%token VOID NEW RETURN

%token IF ELSE FOR WHILE

%token Board GameState

%token title width height player dice

%token points name direction turnDelay startLocation

%token sides

%token Change GoTo Delay Direction

%token numPlayers numTurns numRounds currentPlayer activePlayer running

%token GameOver Winner InitializeBoard InitializeCells

%token INT_LITERAL DOUBLE_LITERAL STRING_LITERAL BOOLEAN_LITERAL

%token ID COMMA SEMI ASSIGN DOT

%token LBRACE RBRACE LPAREN RPAREN LBRACK RBRACK

%token LESS_EQ GRT_EQ NOT_EQ EQUAL AND OR

%token INC DEC

%nonassoc IFX
%nonassoc ELSE
%right ASSIGN
%left OR AND
%left EQUAL NOT_EQ
%left "<" ">" LESS_EQ GRT_EQ
%left DOT LBRACK
%left "+" "-"
%left "*" "/"
%left INC DEC
%right "!"
%right UMINUS

%%

lines: lines fun_def { root.children.add((BGDLTreeNode)$2.obj);}
		  | 
  		;

/* FUNCTIONS */
fun_def: datatype_function ID LPAREN RPAREN block
      { BGDLTreeNode current = new BGDLTreeNode("function"); 
    	current.children.add((BGDLTreeNode)$1.obj); 
    	current.children.add(new BGDLTreeNode($2.sval)); 
    	current.children.add((BGDLTreeNode)$5.obj); 
    	$$.obj = current;
	 	if(!check.checkFunctionType((BGDLTreeNode)$1.obj, $2.sval))
	 		checkType = false; 
		check.setCurrentFuncName($2.sval);
		if(!check.compareReturnType())
			checkType = false; }
    	;

datatype_function: datatype
			| complexType LBRACK RBRACK

/* DECLARATION */
basicType: INT { $$.obj = new BGDLTreeNode("int"); }
      | DOUBLE { $$.obj = new BGDLTreeNode("double"); }
      | BOOLEAN { $$.obj = new BGDLTreeNode("boolean"); }
      | String { $$.obj = new BGDLTreeNode("String"); }
      | VOID { $$.obj = new BGDLTreeNode("void"); }
      ;

complexType: Player { $$.obj = new BGDLTreeNode("Player", "Player"); }
      | Dice { $$.obj = new BGDLTreeNode("Dice", "Dice"); }
      ;

datatype: basicType | complexType
      ;

decl: var_decl
      | array_decl
      ;

var_init: datatype ID
      { BGDLTreeNode current = new BGDLTreeNode("var_init"); 
    	current.children.add((BGDLTreeNode)$1.obj); 
    	current.children.add(new BGDLTreeNode($2.sval));
    	$$.obj = current; 
    	check.addVariableToTable((BGDLTreeNode)$1.obj, $2.sval); }
    	;

complexType_new: NEW complexType LPAREN expr_list RPAREN
      { BGDLTreeNode current = new BGDLTreeNode("new"); 
    	current.children.add((BGDLTreeNode)$2.obj); 
    	current.children.add((BGDLTreeNode)$4.obj);
    	$$.obj = current; 
    	if(!check.compareParamList((BGDLTreeNode)$2.obj))
    		checkType = false; }
    	;

var_decl: var_init
      | var_init ASSIGN expr
      { BGDLTreeNode current = new BGDLTreeNode("=");
    	current.children.add((BGDLTreeNode)$1.obj); 
    	current.children.add((BGDLTreeNode)$3.obj);
    	$$.obj = current; 
    	if(!check.compareIDAssignParam((BGDLTreeNode)$1.obj, (BGDLTreeNode)$3.obj))
    		checkType = false; }
    	
    	| var_init ASSIGN complexType_new
      { BGDLTreeNode current = new BGDLTreeNode("="); 
    	current.children.add((BGDLTreeNode)$1.obj); 
    	current.children.add((BGDLTreeNode)$3.obj);
    	$$.obj = current; 
    	if(!check.compareComplexAssignParam((BGDLTreeNode)$1.obj, (BGDLTreeNode)$3.obj))
    		checkType = false; }
      ;
         
array_init : datatype LBRACK RBRACK ID
      { BGDLTreeNode current = new BGDLTreeNode("array_init"); 
    	current.children.add((BGDLTreeNode)$1.obj); 
    	current.children.add(new BGDLTreeNode($4.sval));
    	$$.obj = current; 
    	check.addVariableToTable((BGDLTreeNode)$1.obj, $4.sval); }
    	;

array_new: NEW datatype LBRACK expr RBRACK
      { BGDLTreeNode current = new BGDLTreeNode("array_new"); 
    	current.children.add((BGDLTreeNode)$2.obj); 
    	current.children.add((BGDLTreeNode)$4.obj);
    	$$.obj = current; }
    	;

array_decl: array_init
      | array_init ASSIGN array_new
      { BGDLTreeNode current = new BGDLTreeNode("="); 
    	current.children.add((BGDLTreeNode)$1.obj); 
    	current.children.add((BGDLTreeNode)$3.obj);
    	$$.obj = current; }
      ;

expr_decl: expr {$$.obj = $1.obj; }
      | decl {$$.obj = $1.obj; }
      ;

/* STATEMENTS */
stmt: expr_decl SEMI {$$.obj = $1.obj; }
      | assign_stmt SEMI {$$.obj = $1.obj; }
      | action_stmt SEMI {$$.obj = $1.obj; }
      | block
      
      | RETURN expr SEMI
      { BGDLTreeNode current = new BGDLTreeNode("return");
  		current.children.add((BGDLTreeNode)$2.obj);
  		$$.obj = current; 
  		check.setReturnType((BGDLTreeNode)$2.obj); }
      
      | IF LPAREN expr RPAREN block %prec IFX
      { BGDLTreeNode current = new BGDLTreeNode("if");
  		current.children.add((BGDLTreeNode)$3.obj);
  		current.children.add((BGDLTreeNode)$5.obj);
  		$$.obj = current; }
  		
      | IF LPAREN expr RPAREN block ELSE stmt 
      { BGDLTreeNode current = new BGDLTreeNode("if-else");
  		current.children.add((BGDLTreeNode)$3.obj);
  		current.children.add((BGDLTreeNode)$5.obj);
		current.children.add((BGDLTreeNode)$7.obj);
  		$$.obj = current; }
      
      | WHILE LPAREN expr RPAREN block 
      { BGDLTreeNode current = new BGDLTreeNode("while");
  		current.children.add((BGDLTreeNode)$3.obj);
  		current.children.add((BGDLTreeNode)$5.obj);
  		$$.obj = current; }
      
      | FOR LPAREN expr_decl SEMI expr SEMI expr RPAREN block
      { BGDLTreeNode current = new BGDLTreeNode("for");
  		current.children.add((BGDLTreeNode)$3.obj);
  		current.children.add((BGDLTreeNode)$5.obj);
  		current.children.add((BGDLTreeNode)$7.obj);
  		current.children.add((BGDLTreeNode)$9.obj);
  		$$.obj = current; }
      ;

block: LBRACE stmt_list RBRACE 
      { BGDLTreeNode current = new BGDLTreeNode("block");
      current.children.add((BGDLTreeNode)$2.obj);
      $$.obj = current; }
      ;

stmt_list: stmt stmt_list 
      { BGDLTreeNode current = new BGDLTreeNode("stmt_list");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$2.obj);
      $$.obj = current; }
      | /* empty */ { $$.obj = new BGDLTreeNode("empty"); }
      ;

/* ASSIGN STMTS */
assign_expr: expr 
      | array_new
      | complexType_new
      ;

assign_stmt: ID ASSIGN assign_expr
      { BGDLTreeNode current = new BGDLTreeNode("=");
  		current.children.add(new BGDLTreeNode($1.sval));
  		current.children.add((BGDLTreeNode)$3.obj);
  		$$.obj = current; 
	  	if(!check.compareIDAssignParam(check.idToType($1.sval), (BGDLTreeNode)$3.obj))
	  		checkType = false; }
  		
      | array_expr ASSIGN assign_expr
      { BGDLTreeNode current = new BGDLTreeNode("=");
  		current.children.add((BGDLTreeNode)$1.obj);
  		current.children.add((BGDLTreeNode)$3.obj);
  		$$.obj = current; }
  		
      | dot_expr ASSIGN assign_expr
      { BGDLTreeNode current = new BGDLTreeNode("=");
  		current.children.add((BGDLTreeNode)$1.obj);
  		current.children.add((BGDLTreeNode)$3.obj);
  		$$.obj = current; 
	  	if(!check.compareDotAssignParam((BGDLTreeNode)$1.obj, (BGDLTreeNode)$3.obj))
	  		checkType = false; }
  		
  		| cell_expr ASSIGN block
      { BGDLTreeNode current = new BGDLTreeNode("=");
  		current.children.add((BGDLTreeNode)$1.obj);
  		current.children.add((BGDLTreeNode)$3.obj);
  		$$.obj = current; }
      ;

/* ACTION STMTS */
action_stmt: ID LPAREN expr_list RPAREN
      { BGDLTreeNode current = new BGDLTreeNode("action");
  		current.children.add(new BGDLTreeNode($1.sval));
  		current.children.add((BGDLTreeNode)$3.obj);
  		$$.obj = current; 
  		if(!check.compareActionParam($1.sval, (BGDLTreeNode)$3.obj))
  			checkType = false; }
  		;
  		

/* EXPRESSIONS */
expr: literal
      | ID { $$.obj = new BGDLTreeNode($1.sval); }
      | op_expr
      | array_expr
      | dot_expr
      | cell_expr
      | LPAREN expr RPAREN { $$.obj = (BGDLTreeNode)$2.obj;};
      ;

expr_list: expr COMMA expr_list 
      { BGDLTreeNode current = new BGDLTreeNode("expr_list");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current;
      check.saveFuncParam((BGDLTreeNode)$1.obj); }
      | expr { check.saveFuncParam((BGDLTreeNode)$1.obj); }
      ;

literal: INT_LITERAL 
      { BGDLTreeNode current = new BGDLTreeNode("INT_LITERAL");
  		current.children.add(new BGDLTreeNode("" + $1.ival, "int"));
  		$$.obj = current; }
  		
      | STRING_LITERAL 
      { BGDLTreeNode current = new BGDLTreeNode("STRING_LITERAL");
  		current.children.add(new BGDLTreeNode($1.sval, "String"));
      $$.obj = current; }
      
      | DOUBLE_LITERAL 
      { BGDLTreeNode current = new BGDLTreeNode("DOUBLE_LITERAL");
  		current.children.add(new BGDLTreeNode("" + $1.dval, "double"));
      $$.obj = current; }
      
      | BOOLEAN_LITERAL 
      { BGDLTreeNode current = new BGDLTreeNode("BOOLEAN_LITERAL");
  		current.children.add(new BGDLTreeNode($1.sval, "boolean"));
      $$.obj = current; }
      ;

binary_expr: expr OR expr
      { BGDLTreeNode current = new BGDLTreeNode("||");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; }
      | expr AND expr
      { BGDLTreeNode current = new BGDLTreeNode("&&");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; }
      | expr "<" expr
      { BGDLTreeNode current = new BGDLTreeNode("<");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current;
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "<"))
	  		checkType = false; }
      | expr ">" expr
      { BGDLTreeNode current = new BGDLTreeNode(">");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current;
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, ">"))
	  		checkType = false; }
      | expr EQUAL expr
      { BGDLTreeNode current = new BGDLTreeNode("==");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current;
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "=="))
	  		checkType = false; }
      | expr NOT_EQ expr
      { BGDLTreeNode current = new BGDLTreeNode("!=");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current;
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "!="))
	  		checkType = false; }
      | expr LESS_EQ expr
      { BGDLTreeNode current = new BGDLTreeNode("<=");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; 
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "<="))
	  		checkType = false; }
      | expr GRT_EQ expr
      { BGDLTreeNode current = new BGDLTreeNode(">=");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; 
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, ">="))
	  		checkType = false; }
      | expr "+" expr
      { BGDLTreeNode current = new BGDLTreeNode("+");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; 
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "+"))
	  		checkType = false; }
      | expr "-" expr
      { BGDLTreeNode current = new BGDLTreeNode("-");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; 
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "-"))
	  		checkType = false; }
      | expr "*" expr
      { BGDLTreeNode current = new BGDLTreeNode("*");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; 
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "*"))
	  		checkType = false; }
      | expr "/" expr
      { BGDLTreeNode current = new BGDLTreeNode("/");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; 
	  if(!check.compareORParam(check.idToType((BGDLTreeNode)$1.obj), (BGDLTreeNode)$3.obj, "/"))
	  		checkType = false; }
      ;
      
unary_expr: expr INC
      { BGDLTreeNode current = new BGDLTreeNode("++");
      current.children.add((BGDLTreeNode)$1.obj);
      $$.obj = current; }
      | expr DEC
      { BGDLTreeNode current = new BGDLTreeNode("--");
      current.children.add((BGDLTreeNode)$1.obj);
      $$.obj = current; }
      | "!" expr
      { BGDLTreeNode current = new BGDLTreeNode("!");
      current.children.add((BGDLTreeNode)$2.obj);
      $$.obj = current; }
      | "-" expr %prec UMINUS
      { BGDLTreeNode current = new BGDLTreeNode("unary -");
      current.children.add((BGDLTreeNode)$2.obj);
      $$.obj = current; }
      ;
      
op_expr: binary_expr | unary_expr
      ;

array_expr: expr LBRACK expr RBRACK 
      { BGDLTreeNode current = new BGDLTreeNode("array_expr");
      current.children.add((BGDLTreeNode)$1.obj);
      current.children.add((BGDLTreeNode)$3.obj);
      $$.obj = current; }
      ;

/* ACCESS EXPR */
dot_expr: expr DOT expr
      { BGDLTreeNode current = new BGDLTreeNode(".");
      current.children.add((BGDLTreeNode) $1.obj);
      current.children.add((BGDLTreeNode) $3.obj);
      $$.obj = current;
	  if(!check.compareAstParam((BGDLTreeNode)$1.obj, (BGDLTreeNode)$3.obj))
	  		checkType = false;  }
      ;

cell_expr: Cell LBRACK expr COMMA expr RBRACK
      { BGDLTreeNode current = new BGDLTreeNode("cell_expr");
      current.children.add(new BGDLTreeNode("Cell"));
  		current.children.add((BGDLTreeNode)$3.obj);
  		current.children.add((BGDLTreeNode)$5.obj);
  		$$.obj = current; 
  		if(!check.compareCellParam((BGDLTreeNode)$3.obj, (BGDLTreeNode)$5.obj))
  			checkType = false; }
  		;

%% 
private scanner lexer; 
//root of the tree
public BGDLTreeNode root;
public checkType check;
public static boolean checkType = true;

private int yylex() { 
	int retVal = -1; 
	try { 
	
	for (int i = 0; i < 1; i++) {
		retVal = lexer.yylex();
		
	}
	
		} 
	catch (IOException e) { System.err.println("IO Error:" + e); } return retVal; 
} 
public void yyerror (String error) { 
	System.err.println("Error : " + error + " at line " + lexer.getLine()); 
	System.err.println("String rejected"); 
} 
public Parser (Reader r)
{
  lexer = new scanner (r, this);
  root = new BGDLTreeNode("program");
  check = new checkType();
} 

public static void main (String [] args) throws IOException {
	Parser yyparser = new Parser(new FileReader(args[0]));
	yyparser.yyparse();
	ScopeCheck scopeCheck = new ScopeCheck(yyparser.root);
	String errorScope = scopeCheck.checking();
	if(checkType&&(errorScope.equals(""))) {
		ASTToJava translation = new ASTToJava(yyparser.root);
		String translationError = translation.translate();
		if(!translationError.equals("")){
			//error found
			System.out.println(translationError);
			System.out.println("Warning: No BoardGame.java output file due to error.");
		}
 	}else{
		System.out.println(errorScope);
	}
} 

